package cn.wolfcode.service.impl;

import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.domain.*;
import cn.wolfcode.mapper.OrderInfoMapper;
import cn.wolfcode.mapper.PayLogMapper;
import cn.wolfcode.mapper.RefundLogMapper;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.IOrderInfoService;
import cn.wolfcode.service.ISeckillProductService;
import cn.wolfcode.util.IdGenerateUtil;
import cn.wolfcode.web.feign.IIntegralFeignApi;
import cn.wolfcode.web.feign.IPayFeignApi;
import cn.wolfcode.web.msg.SeckillCodeMsg;
import com.alibaba.fastjson.JSON;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * Created by wolfcode-lanxw
 */
@Service
public class OrderInfoSeviceImpl implements IOrderInfoService {
    @Autowired
    private ISeckillProductService seckillProductService;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private PayLogMapper payLogMapper;
    @Autowired
    private RefundLogMapper refundLogMapper;

    @Override
    public OrderInfo find(String orderNo) {
        OrderInfo orderInfo = orderInfoMapper.find(orderNo);
        return orderInfo;
    }

    @Override
    public Integer findOrderByPhoneAndSid(String phone, Long seckillId) {
        Integer orderNum = orderInfoMapper.findOrderByPhoneAndSid(phone,seckillId);
        return orderNum;
    }

    @Override
    @Transactional
    public String doSecKill(Integer time, Long seckillId, String phone) {
        // 制造可以正常生成订单但是生成订单失败的异常
        //int i = 1/0;

        // 订单编号，雪花算法生成
        String orderNo = IdGenerateUtil.get().nextId()+ "";
        // 获取秒杀商品的信息
        SeckillProductVo vo = seckillProductService.find(time, seckillId);

        OrderInfo orderInfo = new OrderInfo();

        BeanUtils.copyProperties(vo,orderInfo);

        orderInfo.setOrderNo(orderNo);
        orderInfo.setPhone(phone);
        orderInfo.setCreateDate(new Date());
        orderInfo.setSeckillDate(vo.getStartDate());
        orderInfo.setSeckillTime(time);
        orderInfo.setSeckillId(seckillId);

        // 新增订单
        // insert受影响行，如果为0，说明mysql中的唯一索引起效，也就是已经存在了该手机的指定
        // 商品的订单，手机号码重复下单,sql没有执行成功
        int insert = orderInfoMapper.insert(orderInfo);
        if (insert == 0) {
            throw new BusinessException(SeckillCodeMsg.REPEAT_SECKILL);
        }
        // 现在只有mysql操作了，把redis放到canal那里监听做
        /*// 把该用户的手机号与商品订单的关系以set数据类型存储到redis中，以供判断该用户是否重复下单
        redisTemplate.opsForSet().add(SeckillRedisKey.SECKILL_ORDER_SET.getRealKey(seckillId+""),phone);*/


        // 秒杀商品库存减一
        seckillProductService.decrStockCount(seckillId);
        // 返回订单号
        return orderNo;
    }

    @Override
    @Transactional
    public void cancelOrder(String orderNo) {
        System.out.println(orderNo);
        /*// 查询出 生成的订单
        OrderInfo orderInfo = orderInfoMapper.find(orderNo);
        // 如果是未支付的订单，超时，取消
        if (orderInfo.getStatus().equals(OrderInfo.STATUS_ARREARAGE)) {
            int affectedRows = orderInfoMapper.changeOrderStatus(orderNo
                    , OrderInfo.STATUS_TIMEOUT, orderInfo.getStatus());
            if (affectedRows > 0) {
                // 说明修改成功，库存则要增加1。如果为0，则说明了支付线程已经把订单正常支付了
                seckillProductService.incrStock(orderInfo.getSeckillId());
                // 同步库存到redis中
                seckillProductService.syncStockCount(orderInfo.getSeckillTime(),orderInfo.getSeckillId());
            }
        }*/
    }

    @Autowired
    private IPayFeignApi payFeignApi;
    @Value("${pay.returnUrl}")
    private String returnUrl;
    @Value("${pay.notifyUrl}")
    private String notifyUrl;

    @Override
    public String payOnline(String orderNo) {
        // 通过订单号查询订单
        OrderInfo orderInfo = orderInfoMapper.find(orderNo);
        // 调用支付接口所需要的参数封装对象
        PayVo payVo = new PayVo();
        payVo.setOutTradeNo(orderNo); //订单编号
        payVo.setTotalAmount(orderInfo.getSeckillPrice() + ""); // 付款金额
        payVo.setSubject("消费商品：" + orderInfo.getProductName()); //订单名称
        payVo.setBody(orderInfo.getProductName()); //商品描述
        payVo.setReturnUrl(returnUrl); // 同步回调地址
        payVo.setNotifyUrl(notifyUrl); //异步回调地址

        // 远程调用支付接口返回支付宝付款html页面
        Result<String> result = payFeignApi.pay(payVo);
        if (result == null ||result.hasError()) {
            throw new BusinessException(SeckillCodeMsg.PAY_SERVER_ERROR);
        }
        String html = result.getData();
        return html;
    }

    @Override
    @Transactional
    public void paySuccess(String orderNo) {
        // 更新订单状态
        int effectRows = orderInfoMapper.changePayStatus(orderNo, OrderInfo.STATUS_ACCOUNT_PAID, OrderInfo.STATUS_ARREARAGE, OrderInfo.PAYTYPE_ONLINE);
        // 影响行为0的话
        if (effectRows == 0) {
            // 说明订单的状态不为未支付状态，已经被其他并发线程修改了状态，比如说超时取消
            // 走人工退款逻辑
            return;
        }
        OrderInfo orderInfo = orderInfoMapper.find(orderNo);
        // 插入支付日志表
        PayLog payLog = new PayLog();
        payLog.setOrderNo(orderNo);
        payLog.setPayTime(new Date());
        String price = orderInfo.getSeckillPrice() + "";
        //payLog.setTotalAmount(Long.parseLong(price));
        payLog.setPayType(orderInfo.getPayType());
        payLogMapper.insert(payLog);
    }



    @Override
    public void refundOnline(OrderInfo orderInfo) {
        // 远程调用支付宝退款接口
        RefundVo refundVo = new RefundVo();
        refundVo.setOutTradeNo(orderInfo.getOrderNo()); // 订单号
        refundVo.setRefundAmount(orderInfo.getSeckillPrice() + ""); // 退款金额
        refundVo.setRefundReason("不需要了");
        Result<Boolean> result = payFeignApi.refund(refundVo);
        if (result == null || result.hasError()) {
            throw new BusinessException(SeckillCodeMsg.PAY_SERVER_ERROR);
        }
        if (! result.getData()) {
            // 没有退款成功
            throw new BusinessException(SeckillCodeMsg.PAY_ERROR);
        }
        // 修改订单的状态
        orderInfoMapper.changeOrderStatus(orderInfo.getOrderNo(),OrderInfo.STATUS_REFUND,OrderInfo.STATUS_ACCOUNT_PAID);
    }

    @Autowired
    private IIntegralFeignApi iIntegralFeignApi;

    @Override
    @GlobalTransactional //seata-At分布式事务注解
    public void payIntegral(String orderNo) {
        OrderInfo orderInfo = orderInfoMapper.find(orderNo);
        // 插入日志流水
        PayLog payLog = new PayLog();
        payLog.setOrderNo(orderNo); // 订单号
        payLog.setPayTime(new Date()); // 支付日期
        payLog.setPayType(OrderInfo.PAYTYPE_INTEGRAL); //支付类型
        payLog.setTotalAmount(orderInfo.getIntegral()); //支付所需要的积分
        try {
            payLogMapper.insert(payLog);
        } catch (Exception ex) {
            return;
        }
        // 远程调用积分服务扣减
        OperateIntegralVo operateIntegralVo = new OperateIntegralVo();
        operateIntegralVo.setPhone(orderInfo.getPhone());
        operateIntegralVo.setValue(orderInfo.getIntegral()); // 积分
        Result<Boolean> result = iIntegralFeignApi.pay(operateIntegralVo);
        if (result == null || result.hasError()) {
            throw new BusinessException(SeckillCodeMsg.INTEGRAL_SERVER_ERROR);
        }
        if (! result.getData()) {
            // 积分不够
            throw new BusinessException(SeckillCodeMsg.INTEGRAL_NOT_ENOUGH);
        }
        // 修改订单的状态
        int effectRows = orderInfoMapper.changePayStatus(orderNo, OrderInfo.STATUS_ACCOUNT_PAID, OrderInfo.STATUS_ARREARAGE, OrderInfo.PAYTYPE_INTEGRAL);
        if (effectRows == 0) {
            // 说明订单状态改变了，不是未支付的状态，没有修改成功
            throw new BusinessException(SeckillCodeMsg.ORDER_STATUS_CHANGE);
        }
        try {
            TimeUnit.SECONDS.sleep(20); //等待20秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 制造异常
        //int i = 1/0;
    }

    @Override
    @GlobalTransactional
    public void refundIntegral(OrderInfo orderInfo) {
        // 插入退款日志
        RefundLog refundLog = new RefundLog();
        refundLog.setOrderNo(orderInfo.getOrderNo()); //订单号
        refundLog.setRefundAmount(orderInfo.getIntegral()); // 退款积分数量
        refundLog.setRefundReason("不需要了");
        refundLog.setRefundTime(new Date());
        refundLog.setRefundType(OrderInfo.PAYTYPE_INTEGRAL); // 退款类型
        try {
            refundLogMapper.insert(refundLog);
        } catch (Exception ex) {
            return;
        }

        // 远程调用积分服务
        OperateIntegralVo vo = new OperateIntegralVo();
        vo.setPhone(orderInfo.getPhone());
        vo.setValue(orderInfo.getIntegral());
        Result<Boolean> result = iIntegralFeignApi.refund(vo);
        if (result == null || result.hasError()) {
            throw new BusinessException(SeckillCodeMsg.INTEGRAL_SERVER_ERROR);
        }
        
        // 修改订单状态
        int effectRows = orderInfoMapper.changeOrderStatus(orderInfo.getOrderNo()
                , OrderInfo.STATUS_REFUND
                , OrderInfo.STATUS_ACCOUNT_PAID);
        if (effectRows == 0) {
            throw new BusinessException(SeckillCodeMsg.ORDER_STATUS_CHANGE);
        }
        // int i = 1/0
    }

    @Override
    public OrderInfo findFromCache(String orderNo) {
        String orderHshKey = SeckillRedisKey.SECKILL_PRODUCT_HASH.getRealKey("");
        String objStr = (String)redisTemplate.opsForHash().get(orderHshKey,orderNo);
        return JSON.parseObject(objStr,OrderInfo.class);
    }
}
